# -*- coding: utf-8 -*-
#copyright 2009 Kevin Daley
#This file is a part of Cerebra.
#Cerebra is free software: you can redistribute it and/or modify
 #   it under the terms of the GNU  General Public License as published by
  #  the Free Software Foundation, either version 3 of the License, or
   # (at your option) any later version.

   # This program is distributed in the hope that it will be useful,
   # but WITHOUT ANY WARRANTY; without even the implied warranty of
   # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   # GNU  General Public License for more details.

   # You should have received a copy of the GNU  General Public License
   # along with this program.  If not, see <http://www.gnu.org/licenses/>.

#Kevin Daley, Lead Developer.  still.horse@gmail.com.

import stackless, glob, re, sys, random, numpy, pickle, string, socket, urllib
from PIL import Image as image
import map2 as map
from ctypes import *
from string import *
from math import *
from xml.dom.minidom import parse, parseString
import libcerebra as cerebra
class grammar(map.node, object):
	def __new__(cls, dict=None, *args,**kwds):
		k=object.__new__(cls, " ", *args, **kwds)
		if(dict is None):
			pass
		else:
			c=dict.keys()
			for i in c:
				k.__dict__[i]=dict[i]
		return k
	def __init__(self, *args, **kwds):
		print "passing args to node channel"
		for name in kwds.keys():
			self.__setattr__(name, kwds[name])
	def setup(self):
		if len(self.parents.keys()) !=0:
			self.parent=self.parents[self.parents.keys()[0]] 
			self.neighbors=self.parent.cstrings
		else:
			self.parent=None
			self.neighbors=None
		print "initializing node channel..."
		self.channel = stackless.channel()
		"..creating root node.."
		self.spectrum=(numpy.random.poisson(460,64)).astype(numpy.float64).flatten() if self.parent==None else self.parent.spectrum
		print self.spectrum
		self.input=(numpy.random.poisson(9024,1024*1024+1024*1024*64+1024)).astype(numpy.float64).flatten()
		print self.input
		self.bnd=(numpy.random.poisson(9024,1024*1024+1024*1024*64+1024)).astype(numpy.float64).flatten() if self.parent==None or self.parent.ID==0 else self.parent.input
		print self.bnd
		map.node.__init__(self, parents={}, children={}, ID=random.random(), offset=[0, 0], cstrings=self.spectrum, estring=string.join((self.spectrum).astype(str).tolist()))
		if(self.__dict__.has_key("tasks")):
			self.tasks=pickle.loads(tasks)
			for i in self.tasks:
				i.insert()
		else:
			self.tasks=[]
			t=stackless.tasklet(self.handle_input)()
			self.tasks.append(t)
			t=stackless.tasklet(self.autobalance)()
			self.tasks.append(t)
			t=stackless.tasklet(self.evolve)()
			self.tasks.append(t) 
			t=stackless.tasklet(self.program)()
			self.tasks.append(t)
			t=stackless.tasklet(self.run)()
			self.tasks.append(t)
		print "..channel initialized"
	def handle_input(self):
		stackless.schedule()
		print "header %i: executing __call__ method"%self.ID
		if(not self.__dict__.has_key("programs")):
			self.programs=[]
		while(1):
			stackless.schedule()			
			k=str(self.channelout.receive())
			print "%s, copy."%(k)
			while(len(self.queue.keys())!=0):
				pass
			
			if "!" in k and k[0]!="!":
				print "do something!"
				if not k in self.programs:
					print k
					self.astring=(";"+k.split("!")[0])
					self.programs.append(k)
				elif not ";" in k:
					self.astring=(k.split("!")[0])
			else:
				raise IOError
			s=self.astring
			self.channelout.send(s)
	def attach_out(channelout):
		self.channelout=channelout
	def __setattr__(self, name, value):
		self.__dict__[name]=value
	def dump(self):
		for i in self.children.keys():
			self.children[i].dump()
		print "preparing node %i for deletion, will dump to stdout"%(self.ID)
		if self.__dict__.has_key("network"):
			return map.node.dump(self)				
					
					
class app:
	def __init__(self,HOST=None, PORT=None, subnet=none, ssl_certs=None, input=[], dict=None):
		self.HOST=HOST
		self.PORT=PORT
		self.subnet=subnet
		self.addr=(self.HOST, self.PORT)
		self.ssl_certs=None
		self.input=input
		self.dict=dict
		self.data=None
		self.channel=stackless.channel()
		stackless.tasklet(self.loop)()
		stackless.tasklet(self.balance)()
		stackless.tasklet(self.connection_handler)()
	def balance(self):
		if self.data!=None:
			if self.data.ID!=0:			
				if self.data.parent!=None:
					self.data=self.data.parent
	def loop(self):
			lp=lambda x,n:1
			n=1
			ch=stackless.channel()
			while(1):
				if len(self.input!=0):
					input=self.input.pop(0)
					try:
						self.doc=parse(input)
					except:
						self.doc=parseString(input)	
					c=self.doc.getElementsByTagName("command")
						self.data=grammar(ID=self.HOST, children={}, cstrings=[], parents={}, estring=str(self.HOST), spectrum=numpy.array([i for i in xrange(self.HOST, self.HOST+64]), dict=self.dict, channelout=ch)
						count=0
						for i in c:
							for counter in xrange(len(i.childNodes)):
								ob0=self.data
								j=i.childNodes[counter]
								n=lp(j,n)
								if j.nodeType!=3 and n:
									inp=j.childNodes[0].nodeValue
									if inp!="....":
										k=j.nodeName
										if k=="desc":
											tmp=0
											while tmp<=32:
												tmp=random.gauss(0,128)+self.HOST
												tmp=random.gauss(0,128)+self.HOST
											ob=grammar(ID=tmp,children={}, parents={}, estring=self.HOST+str(int(inp.split(",")[0])+count+tmp),cstrings=[], channelout=ch, s=(0,0), unit=float(inp.split(",")[1]), timestep=float(inp.split(",")[2]))
											count+=1
											ob0+=ob
											ob0=ob
											ob.setup()
										elif k=="code":
											exec(inp)
										elif (k=="while"):
											lp=eval(inp)
										elif (k=="remote_data"):
											data.__setattr__(j.getAttrbute('key'),numpy.fromfile(urllib.urlget(inp)))
										elif (k=="val"):
											print "broadcast channel %s"%inp
											ch.send(inp.split(":")[1])
											n=ch.receive()
											print "returned %s"%str(n)
											self.output.append((str(n),"<val>%s:[%s=%s]!;</val>"%(str(n),inp.split(":")[1],str(n))))
									else:	
										self.dict=self.data.dump()
										del self.data
										if j.nodeName=="end":
											socket.close()
											sys.exit(0)
	def connection_handler(self):
		stackless.schedule()
		while 1:
			try:
				s = socket.socket(socket.AF_INET, socket.SOCK_STREAM, socket.getprotobyname("ip"))
			except socket.error, msg:
				s = None
				continue
			s.setblocking(0)
			try:
				s.bind(sa)
				s.listen(1)
			except socket.error, msg:
				s.close()
				s = None
				continue
			break
		if s is None:
			print 'could not open socket'
			sys.exit(1)
		while 1:
			stackless.schedule()
			socket.listen(5)
			self.conn, self.addr = s.accept()
			print 'Connected by', self.addr
			while 1:
				data = self.conn.recv(4096)
				if not data: break
				self.input.append(data)
			self.conn.close()
	def route(self):
		stackless.schedule()
		print 'trying to open the socket'
		while 1:
			try:
				s = socket.socket(socket.AF_INET, socket.SOCK_STREAM, socket.getprotobyname("ip"))
			except socket.error, msg:
				s = None
				continue
			s.setblocking(0)
			try:
				s.bind(sa)
				s.listen(1)
			except socket.error, msg:
				s.close()
				s = None
				continue
			break
		if s is None:
			print 'could not open socket'
			sys.exit(1)
		s.setblocking(0)
		while 1:
			stackless.schedule()
			if len(output!=0):
				tmp=self.output.pop()
				tmp2=random.randint(1,100)
				self.conn2=s.connect((int(tmp[0])+self.HOST*self.subnet, self.PORT))
				self.conn2.send(tmp[1])
				self.conn2.close()
def main():
	print "ON"
	k=app(sys.argv[1], sys.argv[2], sys.argv[3])
	t=stackless.run()
	print "OFF"
if __name__=="__main__":
	main()

